package com.gyj.server.core;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * 检测服务是否存在的组件
 * @author Gao
 * @date 2021/6/26
 */
public class ServiceAliveMonitor {

    private static final Logger logger = LogManager.getLogger(ServiceAliveMonitor.class);

    private ServiceRegistry registry = ServiceRegistry.getInstance();

    /**
     * 线程检查间隔时间默认60s
     */
    private static final long  CHECK_ALIVE_INTERVAL = 60 * 1000L;

    public ServiceAliveMonitor() {
        this.daemon = new Daemon();
        //设置了标志位，表示这个线程是一个daemon后台线程，非daemon线程我们一般称为工作线程
        //如果工作线程(main)线程结束了，daemon线程不会阻止jvm进程退出
        //daemon会跟着jvm进程一起退出
        daemon.setDaemon(true);
        daemon.setName("ServiceAliveMonitor");
    }

    /**
     * 检测服务实例是否存活的线程
     */
    private Daemon daemon;

    /**
     * 启动
     */
    public void start() {
        this.daemon.start();
    }

    /**
     * 检查服务是否存活的线程
     */
    private class Daemon extends Thread {

        @Override
        public void run() {
            Map<String, Map<String, ServiceInstance>> registryMap;
            while (true) {
                try {
                    // 判断是否需要开启自我保护模式
                    SelfProtectionPolicy selfInstance = SelfProtectionPolicy.getInstance();
                    if (selfInstance.isEnable()) {
                        logger.info("检查服务是否存活的线程，开启自我保护模式，不用摘除服务实例");
                        Thread.sleep(CHECK_ALIVE_INTERVAL);
                        continue;
                    }
                    logger.info("检查服务是否存活的线程, 获取注册表到单例registry:{}", registry);

                    // 定义要删除的服务实例
                    List<ServiceInstance> removeServiceInstances = new ArrayList<>();
                    try {
                        registry.readLock();
                        registryMap = registry.getRegistry();
                        logger.info("[检查服务是否存活的线程], 获取全量注册表, 加读锁registryMap:{}", registryMap);
                        // 遍历服务查看存活状态
                        for (Map.Entry<String, Map<String, ServiceInstance>> entry : registryMap.entrySet()) {
                            Map<String, ServiceInstance> value = entry.getValue();
                            for (Map.Entry<String, ServiceInstance> serviceEntry : value.entrySet()) {
                                ServiceInstance serviceInstance = serviceEntry.getValue();
                                // 如果这个服务实例距离上一次发送心跳超过90s，则移除这个实例
                                if (!serviceInstance.isAlive()) {
                                    removeServiceInstances.add(serviceInstance);
                                }
                            }
                        }
                    } finally {
                        logger.info("[检查服务是否存活的线程]释放读锁");
                        registry.readUnlock();
                    }

                    // 将所有的要删除的服务实例，从服务注册表删除
                    for (ServiceInstance serviceInstance : removeServiceInstances) {
                        registry.remove(serviceInstance.getServiceName(), serviceInstance.getServiceInstanceId());
                        // 更新自我保护机制阈值
                        synchronized (SelfProtectionPolicy.class) {
                            selfInstance.setExpectedHeartbeatRate(selfInstance.getExpectedHeartbeatRate() - 2);
                            selfInstance.setExpectedHeartbeatThreshold((long) (selfInstance.getExpectedHeartbeatRate() * 0.85));
                        }
                    }

                    // 过期缓存
                    if (removeServiceInstances.size() > 0) {
                        logger.info("检查服务是否存活的线程, 摘除服务，过期缓存");
                        ServiceRegistryCache.getInstance().invalidate();
                    }

                    Thread.sleep(CHECK_ALIVE_INTERVAL);
                } catch (Exception e) {
                    logger.info("检查服务是否存活的线程, 异常e:{}", e);
                }
            }
        }
    }
}
